home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / INTER53E.ZIP / INTPRINT.C < prev    next >
C/C++ Source or Header  |  1996-02-10  |  62KB  |  2,288 lines

  1. /************************************************************************/
  2. /* INTPRINT.C by Ralf Brown.  Donated to the Public Domain.        */
  3. /* Please do not remove my name from any copies or derivatives.        */
  4. /************************************************************************/
  5. /* Program History:                            */
  6. /*   v1.00  4/23/89  initial public release                */
  7. /*             with 4/30/89 list                    */
  8. /*   v1.10  5/21/89  added -I and -f                    */
  9. /*   v1.11  1/6/90   fixed #endif's for compilers which don't handle    */
  10. /*             labels                        */
  11. /*   v1.20  6/8/90   added -r                        */
  12. /*   v1.30  7/14/90  added -b, tables now stay aligned on odd indents    */
  13. /*   v1.40  10/6/90  added -B based on changes by Naoto Kimura, -w    */
  14. /*   v1.40a 5/6/91   HP LaserJet II support by Russ Herman        */
  15. /*   v1.41  7/9/91   HP PCL support by P.J.Farley III            */
  16. /*   v2.00  9/1/91   modular printer definitions            */
  17. /*             printing multipart interrupt list            */
  18. /*   v2.01  2/9/92   fixed summary entry for non-numeric AX= and AH=    */
  19. /*             smarter page breaks                */
  20. /*   v2.02  2/18/92  bugfix & isxdigit suggested by Aaron West        */
  21. /*   v2.10  3/14/92  updated to handle extra flags in headings        */
  22. /*   v2.11  5/23/92  bugfix pointed out by Joe White            */
  23. /*   v2.20  6/12/92  added -F based on code by Richard Brittain        */
  24. /*             added -H and Panasonic printer def by Lewis Paper    */
  25. /*   v2.21  10/14/92 fixed error in -H/-r interaction            */
  26. /*             updated for new 'Bitmask of' section        */
  27. /*   v2.22   2/15/93 exclude Index: by default, -x to force inclusion    */
  28. /*             changed 'Bitmask of' to 'Bitfields for'        */
  29. /*   v2.23   5/24/93 fix to allow INT/AL= to appear correctly in summary*/
  30. /*   v2.24   7/15/93 -k and infinite-length pages by Bent Lynggaard    */
  31. /*   v3.00   6/4/94  -T, -V, and multi-file break section skipping    */
  32. /*             major speedups; checked for BC++3.1 compatibility    */
  33. /*   v3.01   6/11/94 bugfix: crashed with -l0 -L1 on lines >=80 chars   */
  34. /*   v3.02   1/7/95  bugfix by Mark Shapiro: garbage with -B -PHP_PCL    */
  35. /*   v3.03   1/14/95 changes for Borland C++ 4.x size minimization    */
  36. /*   v3.04   3/25/95 malloc/sbrk and other bugfixes                */
  37. /*   v3.10   2/11/96 category filters by Bent Lynggard            */
  38. /************************************************************************/
  39. /* Recompiling:                                */
  40. /*   Turbo C / Borland C++                        */
  41. /*    tcc -mt -lt -O -a -Z -p -k- intprint                */
  42. /*      bcc -mt -lt -a -d -O1agim -p intprint.c                */
  43. /*   Borland C++ 4.x (as .EXE, from John <tenthumbs@bix.com>)        */
  44. /*    bcc -ms -a -d -O1agim -p intprint.c noehs.lib            */
  45. /************************************************************************/
  46.  
  47. #include <ctype.h>
  48. #include <fcntl.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include <sys/stat.h>        /* S_IREAD, S_IWRITE */
  53.  
  54. #define VERSION "3.10"
  55.  
  56. /***********************************************/
  57. /*    portability definitions               */
  58.  
  59. #define _other_        /* assume no system-specific match */
  60.  
  61. /*--------------------------------------------------*/
  62. /* first system: MS-DOS with Turbo/Borland C        */
  63.  
  64. #ifdef __TURBOC__
  65. #  define PROTOTYPES
  66. #  include <alloc.h>
  67. #  include <io.h>    /* open, close, read, lseek, etc. */
  68.    int _Cdecl isatty(int handle) ;
  69.  
  70.    /* definitions to reduce size of executable */
  71.    unsigned int _Cdecl _stklen = 1024 ;
  72.    #define close _close
  73.    #define read _read
  74.    #define write _write
  75.    void _Cdecl _setenvp(void) {} /* don't need environment--don't include it */
  76.    void *_Cdecl malloc(size_t size)
  77.      { void *x = sbrk(size) ; return (x==(char*)-1) ? 0 : x ; }
  78.    void _Cdecl free(void *var) { (void)var ; }
  79.    /* since our free() doesn't do anything, macro it out of existence */
  80.    #define free(p)
  81.  
  82.    #ifdef __BORLANDC__
  83.    void _Cdecl _setupio(void) {}
  84.    #pragma warn -eff
  85.    /* BC++ v3.1 sets __BORLANDC__ to 0x0410!! */
  86.    #if __BORLANDC__ >= 0x0400 && __BORLANDC__ != 0x0410
  87.    /* Changes by John Sasse to minimize executable size */
  88.    #if 1
  89.       /* the preferred way */
  90.       /* Borland claims they "might" stop supporting these functions. Right */
  91.       #define   _close(a)      _rtl_close(a)
  92.       #define   _creat(a,b)    _rtl_creat(a,b)
  93.       #define   _open(a,b)     _rtl_open(a,b)
  94.       #define   _read(a,b,c)   _rtl_read(a,b,c)
  95.       #define   _write(a,b,c)  _rtl_write(a,b,c)
  96.       #if __BORLANDC__ == 0x400
  97.       /* They forgot to change this in 4.00 only */
  98.       #undef    _read
  99.       #endif
  100.    #else
  101.       #pragma warn -obs    /* the easy way */
  102.    #endif /* 1 */
  103.    #endif /* __BORLANDC__ >= 0x400 */
  104.    #endif /* __BORLANDC__ */
  105.  
  106. #undef _other_
  107. #endif /* __TURBOC__ */
  108.  
  109. #ifdef __MSDOS__
  110. #  define LINE_TERMINATOR '\n'
  111. #endif
  112.  
  113. /*--------------------------------------------------*/
  114. /*   Gnu C compiler                                 */
  115.  
  116. #ifdef __GNUC__
  117. #define PROTOTYPES
  118. #define NEED_ITOA
  119. #define NEED_ULTOA
  120. #define NEED_STRUPR
  121. #define NEED_STRNICMP
  122.  
  123. #undef _other_
  124. #endif /* __GNUC__ */
  125.  
  126. /*--------------------------------------------------*/
  127. /*  generic Unix definitions                        */
  128.  
  129. #ifdef unix
  130. #  include <sys/unistd.h>    /* open, close, read, lseek, etc. */
  131. #  include <sysent.h>        /* open, close, read, lseek, etc. */
  132. extern int isatty(int) ;
  133. #  define LINE_TERMINATOR '\n'
  134. #endif
  135.  
  136.  
  137. /*--------------------------------------------------*/
  138. /*  any other system                                */
  139.  
  140. #ifdef _other_
  141. /* unknown compiler/system, so set configuration #defines */
  142. #if 0  /* set to 1 if compiler supports ANSI-style prototypes, 0 otherwise */
  143. #define PROTOTYPES
  144. #endif
  145. #if 1  /* set to 0 if library contains strnicmp(), 1 otherwise */
  146. #define NEED_STRNICMP
  147. #endif
  148. #if 1  /* set to 0 if library contains isxdigit(), 1 otherwise */
  149. #define NEED_ISXDIGIT
  150. #endif
  151. #if 1  /* set to 0 if library contains strupr(), 1 otherwise */
  152. #define NEED_STRUPR
  153. #endif
  154. #if 1  /* set to 0 if library contains three-arg itoa(), 1 otherwise */
  155. #define NEED_ITOA
  156. #endif
  157. #if 1  /* set to 0 if library contains three-arg ultoa(), 1 otherwise */
  158. #define NEED_ULTOA
  159. #endif
  160.  
  161. #endif /* _other_ */
  162.  
  163. /*--------------------------------------------------*/
  164.  
  165. /* the last character of the line termination sequence, i.e. '\n' for CRLF */
  166. /* and LF, '\r' if your system uses CR or LFCR */
  167. #ifndef LINE_TERMINATOR
  168. #define LINE_TERMINATOR '\n'
  169. #endif /* LINE_TERMINATOR */
  170.  
  171. /*--------------------------------------------------*/
  172. /*  catchall for macros which might not be defined  */
  173.  
  174. #ifndef O_BINARY
  175. #  define O_BINARY 0
  176. #endif
  177.  
  178. #ifndef _Cdecl
  179. #  define _Cdecl
  180. #endif
  181.  
  182. /***********************************************/
  183.  
  184. #ifndef FALSE
  185. #define FALSE 0
  186. #endif
  187. #ifndef TRUE
  188. #define TRUE !FALSE
  189. #endif
  190.  
  191. /***********************************************/
  192.  
  193. #define MAXLINE 82   /* at most 80 chars per line (plus CR and newline) */
  194. #define MAXPAGE 200  /* at most 200 lines per page */
  195.  
  196. #define lengthof(x) (sizeof(x)/sizeof(x[0]))
  197.  
  198. #ifdef __MSDOS__
  199. #define chars_to_long(a, b, c, d) \
  200.     (a | (((long)b)<<8) | (((long)c)<<16) | (((long)d)<<24))
  201. #define long_div_line chars_to_long('-','-','-','-')
  202. #define divider_line(line) (((long*)line)[0] == long_div_line && \
  203.   ((long*)line)[1] == long_div_line)
  204. #define start_of_entry(s) (((long*)s)[0]==chars_to_long('I','N','T',' '))
  205. #define index_line(l) \
  206.   (((long*)l)[0]==chars_to_long('I','n','d','e')&& \
  207.    ((short*)l)[2]==('x'+':'*0x100))
  208. #else
  209. static char long_chars[] = "----INT Index:" ;
  210. #define divider_line(line) (((long*)line)[0] == ((long*)long_chars)[0]\
  211.   && ((long*)line)[1] == ((long*)long_chars)[0])
  212. #define start_of_entry(s) (((long*)s)[0] == ((long*)long_chars)[1])
  213. #define index_line(line) (((long*)line)[0] == ((long*)long_chars)[2] && \
  214.   ((short*)line)[2] == (short*)long_chars)[6])
  215. #endif
  216. #define section_start(line) is_keyword(line,section_start_keys,lengthof(section_start_keys))
  217. #define start_of_table(line) (is_keyword(line,table_start_keys,lengthof(table_start_keys)))
  218.  
  219. #define section_file_start(s) (s[0] == '-' && memcmp(s+1,"-------!---Section",18) == 0)
  220.  
  221.  
  222. /* category filters definitions and variables */
  223. #define CF_BUFFER_SIZE 26+26+9
  224. typedef enum {CF_EXCLUDE, CF_UNCONDITIONAL, CF_INCLUDE, CF_OVERRIDE,
  225.     CF_ENUM_SIZE} CF_ENUM; /* leave CF_ENUM_SIZE as the last enumetator */
  226. char cf_buffers[CF_ENUM_SIZE][CF_BUFFER_SIZE+1];
  227. char cf_current_category;
  228. #define CF_EXCLUDE_CHAR '<'
  229. #define CF_UNCONDITIONAL_CHAR '>'
  230. #define CF_INCLUDE_CHAR 'i'
  231. #define CF_OVERRIDE_CHAR 'o'
  232.  
  233. /***********************************************/
  234. /*    stub functions to reduce executable size */
  235. /***********************************************/
  236.  
  237. #ifdef __BORLANDC__
  238. /* Changes by John Sasse */
  239. /* BC++ v3.1 sets __BORLANDC__ to 0x0410!!  */
  240. #if __BORLANDC__ >= 0x0400 && __BORLANDC__ != 0x0410
  241. /*      Everything within this conditional may be placed in
  242.  *      a separate source file if desired.
  243.  */
  244.  
  245. /* stack overflow checking can never be allowed inside
  246.    the run-time library */
  247. #pragma option -N-
  248.  
  249. #include <errno.h>
  250. /* the next 3 include files are necessary only if this
  251.    is compiled as a separate file */
  252. #if 0
  253. #include <io.h>
  254. #include <stdlib.h>
  255. #include <string.h>
  256. #endif
  257.  
  258. /* declarations */
  259. void _Cdecl      __ErrorMessage (const char *__message);
  260. int  pascal near __IOerror (int  _doserror_);
  261. int  pascal near __DOSerror (int  _doserror_);
  262. void _Cdecl      _abort (void);
  263.  
  264.  
  265. /* may be referenced by a lot of things */
  266. int _Cdecl _doserrno = 0;
  267.  
  268. /*
  269.     The _rtl_* functions all call __IOError which originally
  270.     referenced sys_nerr and sys_errlist. Unfortunately, the
  271.     source file for these also contains perror which calls
  272.     fputs. Hence you get lots of extra code.
  273.     This is a very minimal replacement.
  274. */
  275. int pascal near __IOerror(int _doserror_)
  276. {
  277. /* if _doserror_ is < 0, it might be a System V error.
  278.    we don't care */
  279.     _doserrno = (_doserror_ < 0) ? (-1) : _doserror_;
  280.     errno = EIO;        /* a default value */
  281.     return (-1);
  282. }
  283.  
  284. /* __DOSerror and __IOerror are in the same source file.
  285.    This may not actually be called. Better safe ...
  286. */
  287. #if 1
  288. int pascal near __DOSerror(int _doserror_)
  289. {
  290.     __IOerror(_doserror_);
  291.     return (_doserror_);
  292. }
  293. #endif
  294.  
  295. /*
  296.    The startup code, among others, references _setargv which
  297.    references abort. The run-time library version says "raise
  298.    (SIGABRT)", bringing in a lot of unnecessary code.
  299. */
  300. void _Cdecl abort (void)
  301. {
  302.     _abort ();
  303. }
  304.  
  305. /* necessary to avoid referencing _streams */
  306. #if 1
  307. #define STDERR      2
  308.  
  309. void _Cdecl __ErrorMessage(const char *msg)
  310. {
  311.     _rtl_write(STDERR, msg, strlen(msg));
  312. }
  313. #endif
  314.  
  315. /* restore command line state; note the "." */
  316. #pragma option -N.
  317.  
  318. #endif  /* __BORLANDC__ >= 0x400 */
  319. #endif  /* __BORLANDC__ */
  320.  
  321. /***********************************************/
  322. /*    replacement file I/O function macros     */
  323. /***********************************************/
  324.  
  325. typedef struct
  326.    {
  327.    int fd ;
  328.    int buf_maxsize ;
  329.    char *buf ;
  330.    unsigned long bufoffset ;
  331.    int bufsize ;
  332.    int bufpos ;
  333.    int write ;             /* file is output file if nonzero */
  334.    } IP_FILE ;
  335.  
  336. #define ip_putc(c,fp) \
  337.   ((fp)->buf[fp->bufpos++]=(c),\
  338.    ((fp)->bufpos>=(fp)->buf_maxsize&&ip_flush(fp)==-1)?-1:0)
  339.  
  340. /* output the indicated counted string to the given file */
  341. #define ip_putcstr(s,fp) ip_write((s)->str,(s)->len,fp)
  342. /* output the given string literal to the indicated file */
  343. #define ip_putlit(s,fp) ip_write((s),sizeof(s)-1,fp)
  344. /* output the given string variable to the indicated file */
  345. #define ip_puts(s, fp) ip_write(s,strlen(s),fp)
  346.  
  347. #ifdef __MSDOS__
  348. #define newline(fp) ip_write("\r\n",2,fp)
  349. #else
  350. #define newline(fp) ip_putc('\n',fp)
  351. #endif
  352.  
  353. /***********************************************/
  354.  
  355. typedef struct             /* a counted string */
  356.    {
  357.    int len ;             /* the string's length */
  358.    char *str ;             /* the actual contents of the string */
  359.    } cstr ;
  360.  
  361. #define CSTR(s) { sizeof(s)-1, (s) }  /* for defining a counted string literal */
  362. #define cstrlen(s) ((s)->len)     /* how long is the counted string? */
  363.  
  364. typedef struct
  365.    {
  366.    char *name ;            /* for selecting the appropriate printer */
  367.    cstr init1, init2 ;        /* initialization strings */
  368.    cstr marginl, marginc, marginr ; /* margins: duplex even, non-duplex, duplex odd */
  369.    cstr duplex_on ;        /* turn on duplex mode */
  370.    cstr term1, term2 ;        /* cleanup strings */
  371.    cstr bold_on, bold_off ;    /* boldface on/off */
  372.    int indent ;            /* how many extra spaces to indent */
  373.    int lines_per_page ;        /* how many lines to print on each page */
  374.    int page_length ;        /* how many lines on each page */
  375.    int page_width ;        /* how many printable columns per line? */
  376. #ifdef PROTOTYPES
  377.    void (*put_line)(IP_FILE *,int) ;/* function to call to print out divider line */
  378.    void (*set_typeface)(IP_FILE *,char *) ;
  379. #else
  380.    void (*put_line)() ;        /* function to call to print out divider line */
  381.    void (*set_typeface)() ;
  382. #endif /* PROTOTYPES */
  383.    int *flag ;            /* flag to set when using this printer definition */
  384.    } PRINTER_DEF ;
  385.  
  386. typedef struct filter_list
  387.    {
  388.    struct filter_list *next ;
  389.    char str[1] ;        /* will allocate enough for actual string */
  390.    } FILT_LIST ;
  391.  
  392. typedef struct
  393.    {
  394.    int part ;
  395.    int first_on_page ; /* TRUE if a new entry starts at the top of the page */
  396.    char desc[24] ;
  397.    int len ;
  398.    } HEADER ;
  399.  
  400. typedef struct
  401.    {
  402. /*   char *name ;*/
  403.    char name[14] ;
  404.    int length ;
  405.    } KEYWORDS ;
  406.  
  407. /***********************************************/
  408.  
  409. #ifdef PROTOTYPES
  410. void usage(void) ;
  411. void fatal(char *msg) ;
  412. void warning(char *msg) ;
  413. int unwanted_section(char *buf) ;
  414. IP_FILE *ip_fdopen(int fd,char *buf,int bufsiz, int maxsiz, int write) ;
  415. IP_FILE *ip_open_write(char *name, int trunc, char *buf, int bufsiz) ;
  416. IP_FILE *ip_open_read(char *name, char *buf, int bufsiz) ;
  417. int ip_close(IP_FILE *fp) ;
  418. unsigned long ip_fgets(char *buf, int max, IP_FILE *fp) ;
  419. int ip_write(char *buf, int count, IP_FILE *fp) ;
  420. int ip_flush(IP_FILE *fp) ;
  421. void get_raw_line(char *buf) ;
  422. void get_line(char *buf) ;
  423. void indent_to(int where,IP_FILE *fp) ;
  424. void put_line(IP_FILE *fp, int len) ;
  425. void HPPCL_put_line(IP_FILE *fp, int len) ;
  426. void HPPCL_set_typeface(IP_FILE *fp,char *typeface) ;
  427. int is_keyword(char *s, KEYWORDS *keys, unsigned int numkeys) ;
  428. void output_line(char *line,IP_FILE *fp) ;
  429. void fill_buffer(int lines, int lines_per_page) ;
  430. int find_page_break(int lines) ;
  431. int summarize(int line, int pages_printed) ;
  432. void start_format(char *line) ;
  433. void write_summary_header(IP_FILE *fp, char *title, int offsets, int tables) ;
  434. void show_offset(int line,IP_FILE *fp) ;
  435. void add_table(int i) ;
  436. void add_category_filter_info(CF_ENUM filter, char *str) ;
  437. FILT_LIST *add_filter_info(FILT_LIST *list,char *str) ;
  438. void build_filter_lists(char *file) ;
  439. int make_description(char *desc,int line) ;
  440. char *determine_heading(int last) ;
  441. void print_buffer(int last,int body_lines,int lines_per_page,int total_lines,
  442.           int use_FF) ;
  443. void select_printer(char *name) ;
  444. void display_printers(void) ;
  445. static void reset_printer_and_close(IP_FILE *fp) ;
  446. int _Cdecl main(int argc, char **argv) ;
  447. #else
  448. void put_line() ;
  449. void HPPCL_put_line() ;
  450. void HPPCL_set_typeface() ;
  451. void show_offset() ;
  452. #endif /* PROTOTYPES */
  453.  
  454. /***********************************************/
  455. /*    I/O buffers                   */
  456. /***********************************************/
  457.  
  458. char stderr_buf[1] ;
  459. char filter_buf[256] ;
  460. char infile_buf[8192] ;
  461. char outfile_buf[8192] ;
  462. char summary_buf[4096] ;
  463. char formats_buf[3072] ;
  464. char tables_buf[3072] ;
  465.  
  466. /***********************************************/
  467.  
  468. IP_FILE *err ;
  469. IP_FILE *infile ;
  470. IP_FILE *outfile ;
  471. char *input_file ;
  472. int input_file_namelen ;
  473.  
  474. char buffer[MAXPAGE][MAXLINE] ;
  475. unsigned long line_offsets[MAXPAGE] ;
  476. char num[8] ;
  477. int need_summary ;
  478. char summary_line[2*MAXLINE] ;
  479. int summary_line_len ;
  480.  
  481. int pages_printed = 0 ;
  482. int page_width = 0 ;        /* page width in characters, 0 = use prtdef */
  483. int indent = 0 ;            /* number of columns to indent lines */
  484. char *indent_string = NULL ;    /* what to add at start of line to indent */
  485. int indent_len = 0 ;            /* length of indent_string */
  486. int widow_length = 8 ;        /* number of lines to scan for good place to break */
  487. int page_numbers = FALSE ;    /* add page numbers to bottom of page? */
  488. int multi_file = FALSE ;    /* printing multipart interrupt list? */
  489. int out_of_files = FALSE ;    /* hit end of last file for multipart printing? */
  490. int do_summary = FALSE ;    /* create a one-line-per-call summary? */
  491. int do_tables = FALSE ;        /* create a one-line-per-table index? */
  492. int do_formats = FALSE ;    /* create a separate file with data structures? */
  493. int do_filter = FALSE ;        /* using a filtering file? */
  494. int do_headers = FALSE ;    /* add page headings? */
  495. int include_index_lines = FALSE ;
  496. int IBM_chars = FALSE ;        /* printer can handle IBM graphics characters */
  497. int boldface = FALSE ;        /* boldface titles and Return:/Notes: ? */
  498. int printer_bold = FALSE ;    /* boldface using printer control sequences? */
  499. int echo_format = FALSE ;
  500. int duplex = FALSE ;
  501. int HPPCL_mode = FALSE ;
  502. int show_offsets = FALSE ;
  503. int keep_divider_lines = FALSE ;
  504. int exclude_only = TRUE ;
  505. IP_FILE *summary ;
  506. IP_FILE *tables ;
  507. IP_FILE *formats ;
  508. PRINTER_DEF *printer = NULL ;
  509.  
  510. unsigned long current_line_offset = 0 ;
  511. unsigned long offset_adjust = 0 ;
  512.  
  513. unsigned int first_page = 0 ;
  514. unsigned int last_page = ~0 ;
  515.  
  516. int prev_table = 0 ;
  517.  
  518. FILT_LIST *includes = NULL ;
  519. FILT_LIST *excludes = NULL ;
  520.  
  521. HEADER header_first = { 0, FALSE, "" } ;
  522. HEADER header_last = { 0, FALSE, "" } ;
  523.  
  524. /***********************************************/
  525.  
  526. PRINTER_DEF printers[] =
  527.    {
  528.      { "default",
  529.        CSTR(""), CSTR(""),
  530.        CSTR(""), CSTR(""), CSTR(""),
  531.        CSTR(""),
  532.        CSTR(""), CSTR(""),
  533.        CSTR(""), CSTR(""),
  534.        -1,
  535.        60,
  536.        0,
  537.        79,
  538.        put_line,
  539.        NULL,
  540.        NULL,
  541.      },
  542.      { "Epson FX80, 12 cpi",
  543.        CSTR("\033M"), CSTR(""),
  544.        CSTR("\033l\004"), CSTR("\033l\007"), CSTR("\033l\014"),
  545.        CSTR(""),
  546.        CSTR("\033P"), CSTR("\033l\000"),
  547.        CSTR("\033E"), CSTR("\033F"),
  548.        0,
  549.        60,
  550.        0,
  551.        87,    /* 96 - left margin - 1 right margin */
  552.        put_line,
  553.        NULL,
  554.        NULL,
  555.      },
  556.      { "Panasonic KX-P1124i / 10 cpi Epson",
  557.        CSTR(""), CSTR(""),
  558.        CSTR(""), CSTR(""), CSTR(""),
  559.        CSTR(""),
  560.        CSTR(""), CSTR(""),
  561.        CSTR("\033E"), CSTR("\033F"),
  562.        -1,
  563.        60,
  564.        0,
  565.        79,
  566.        put_line,
  567.        NULL,
  568.        NULL,
  569.      },
  570.      { "HP PCL",
  571.        CSTR("\033(8U"), CSTR(""),
  572.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  573.        CSTR("\033&l1S"),
  574.        CSTR("\033E"), CSTR(""),
  575.        CSTR("\033(s3B"), CSTR("\033(s0B"),
  576.        0,
  577.        69,
  578.        0,
  579.        87,    /* 96 - left margin - 1 right margin */
  580.        HPPCL_put_line,
  581.        HPPCL_set_typeface,
  582.        &HPPCL_mode,
  583.      },
  584. #define HPPCL_FONT_ON_A "\033(s0p12h10v0s0b"
  585. /* HP PCL4/5 Font select: Roman-8;Upright12Pitch10PointMediumWeight */
  586. #define HPPCL_FONT_ON_B "T\033&l6.8571C"
  587. /* HP PCL4/5 Font select: End typeface select;VMI=7LPI: (48/7)-48th's inches*/
  588. #define HPPCL_IBM_LN_A    "\033&f0S\033*p-15Y\033*c"
  589. /* HP PCL4/5 IBM Line:    Push Pos;Up 15/720";Hor.Rule ???/300ths" long */
  590. #define HPPCL_IBM_LN_B    "a3b0P\033&f1S"
  591. /* HP PCL4/5 IBM Line:     3/300ths" high,Print rule;Pop Position */
  592.      { "LaserJet II",
  593.        CSTR("\033(10U"),CSTR(""),
  594.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  595.        CSTR(""),
  596.        CSTR("\033E"),CSTR(""),
  597.        CSTR("\033(s3B"),CSTR("\033(s0B"),
  598.        0,
  599.        54,
  600.        60,
  601.        79,
  602.        put_line,
  603.        NULL,
  604.        &IBM_chars,
  605.      },
  606.    } ;
  607. #define NUM_PRINTERS lengthof(printers)
  608.  
  609. /***********************************************/
  610.  
  611. #define KEYWORD_ENTRY(s) { s, sizeof(s)-1 }
  612.  
  613. KEYWORDS section_start_keys[] =
  614.    {
  615.     KEYWORD_ENTRY("BUG:"),
  616.     KEYWORD_ENTRY("BUGS:"),
  617.     KEYWORD_ENTRY("Desc:"),
  618.     KEYWORD_ENTRY("Index:"),
  619.     KEYWORD_ENTRY("Note:"),
  620.     KEYWORD_ENTRY("Notes:"),
  621.     KEYWORD_ENTRY("Program:"),
  622.     KEYWORD_ENTRY("Range:"),
  623.     KEYWORD_ENTRY("Return:"),
  624.     KEYWORD_ENTRY("SeeAlso:"),
  625.    } ;
  626.  
  627. KEYWORDS table_start_keys[] =
  628.    {
  629.     KEYWORD_ENTRY("Bitfields "),
  630.     KEYWORD_ENTRY("Call "),
  631.     KEYWORD_ENTRY("Format "),
  632.     KEYWORD_ENTRY("Values "),
  633.    } ;
  634.  
  635. /***********************************************/
  636.  
  637. #ifdef isxdigit
  638. #undef NEED_ISXDIGIT
  639. #endif
  640.  
  641. #ifdef NEED_STRNICMP
  642. #ifdef PROTOTYPES
  643. int strnicmp(char *s1,char *s2,unsigned int len) ;
  644. #endif
  645. int strnicmp(s1,s2,len)
  646. char *s1,*s2 ;
  647. unsigned int len ;
  648. {
  649.    char c1, c2 ;
  650.  
  651.    while (*s1 && *s2 && len > 0)
  652.       {
  653.       len-- ;
  654.       c1 = (islower(*s1) ? toupper(*s1) : *s1) ;
  655.       c2 = (islower(*s2) ? toupper(*s2) : *s2) ;
  656.       if (c1 != c2 || len == 0)     /* mismatch or substrings exhausted? */
  657.      return (c1 - c2) ;
  658.       s1++ ;
  659.       s2++ ;
  660.       }
  661.    return 0 ;  /* strings match exactly on first 'len' characters */
  662. }
  663. #endif /* NEED_STRNICMP */
  664.  
  665. #ifdef NEED_STRUPR
  666. #ifdef PROTOTYPES
  667. char *strupr(char *s) ;
  668. #endif
  669. char *strupr(s)
  670. char *s ;
  671. {
  672.    char *orig_s = s ;
  673.    char c ;
  674.    
  675.    if (s)
  676.       while (*s)
  677.      {
  678.      c = *s ;      
  679.      *s++ = (islower(c) ? toupper(c) : c) ;
  680.      }
  681.    return orig_s ;
  682. }
  683. #endif /* NEED_STRUPR */
  684.  
  685. #ifdef NEED_ISXDIGIT
  686. #ifdef PROTOTYPES
  687. int isxdigit(int c) ;
  688. #endif
  689. int isxdigit(c)
  690. int c ;
  691. {
  692.    return isdigit(c) || (memchr("ABCDEFabcdef",c,12) != NULL) ;
  693. }
  694. #endif /* NEED_ISXDIGIT */
  695.  
  696. #ifdef NEED_ITOA
  697. #ifdef PROTOTYPES
  698. char *itoa(int num,char *buf,int radix) ;
  699. #endif
  700. char *itoa(num,buf,radix)   /* not everybody has the same itoa() as TurboC */
  701. int num ;            /* minimal implementation */
  702. char *buf ;
  703. int radix ;
  704. {
  705.    int count = 0 ;
  706.    int i ;
  707.    char tmp ;
  708.  
  709.    do {
  710.       buf[count++] = "0123456789ABCDEF"[num % radix] ;
  711.       num /= radix ;
  712.    } while (num) ;
  713.    buf[count] = '\0' ;
  714.    if (count > 1)
  715.       for (i = 0 ; i < count / 2 ; i++)
  716.      {
  717.      tmp = buf[i] ;
  718.      buf[i] = buf[count-i-1] ;
  719.      buf[count-i-1] = tmp ;
  720.      }
  721.    return buf ;
  722. }
  723. #endif /* NEED_ITOA */
  724.  
  725. #ifdef NEED_ULTOA
  726. #ifdef PROTOTYPES
  727. char *ultoa(unsigned long num,char *buf,int radix) ;
  728. #endif
  729. char *ultoa(num,buf,radix)   /* not everybody has the same ultoa() as TurboC */
  730. unsigned long num ;         /* minimal implementation */
  731. char *buf ;
  732. int radix ;
  733. {
  734.    int count = 0 ;
  735.    int i ; 
  736.    char tmp ;
  737.  
  738.    do {
  739.       buf[count++] = "0123456789ABCDEF"[num % radix] ;
  740.       num /= radix ;
  741.    } while (num) ;
  742.    buf[count] = '\0' ;
  743.    if (count > 1)
  744.       for (i = 0 ; i < count / 2 ; i++)
  745.      {
  746.      tmp = buf[i] ;
  747.      buf[i] = buf[count-i-1] ;
  748.      buf[count-i-1] = tmp ;
  749.      }
  750.    return buf ;
  751. }
  752. #endif /* NEED_ULTOA */
  753.  
  754. /***********************************************/
  755.  
  756. void usage()
  757. {
  758.    ip_putlit("\
  759. Usage: intprint [options] intlist [>|>>]output\r\n\
  760. Options:\r\n\
  761. Filtering:\t-Ffile\tprint only entries matching filtering info in 'file'\r\n\
  762. \t\t-k\tkeep original divider lines\r\n\
  763. \t\t-rN:M\tprint only pages N through M\r\n\
  764. \t\t-x\tinclude Index: lines in formatted output\r\n\
  765. Formatting:\t-b\tboldface headings\t-B\tbold with control codes\r\n\
  766. \t\t-d\t(duplex) print even/odd pages with different indents\r\n\
  767. \t\t-e\t(elite) 96 chars/line\t-tN\tselect typeface N\r\n\
  768. Pagination:\t-H\tadd page headers\t-iN\tindent N spaces\r\n\
  769. \t\t-p\tnumber pages\t\t-nN\tN pages already printed\r\n\
  770. \t\t-wN\twidow lines control\r\n\
  771. \t\t-lN\tprint length\t\t-LN\ttotal page length\r\n\
  772. \t\t\t(0 = infinite)\t(use linefeeds if > #lines printed)\r\n\
  773. Printer:\t-I\tIBM graphics characters\r\n\
  774. \t\t-Pname\tassume printer 'name'\t-P?\tlist printers\r\n\
  775. Summaries:\t-ffile\tdata structure formats\t-sfile\tINT calls\r\n\
  776. \t\t-Tfile\tlist tables\r\n\
  777. Misc:\t\t-m\tprocess multiple parts\t-V\tmake INTERVUE summary\r\n\
  778. "
  779.     ,err) ;
  780.    ip_flush(err) ;
  781.    exit(1) ;
  782. }
  783.  
  784. /***********************************************/
  785.  
  786. void fatal(msg)
  787. char *msg ;
  788. {
  789.    ip_putlit("UNRECOVERABLE ERROR:",err) ;
  790.    newline(err) ;
  791.    ip_puts(msg,err) ;
  792.    newline(err) ;
  793.    ip_flush(err) ;
  794.    exit(1) ;
  795. }
  796.  
  797. /***********************************************/
  798.  
  799. void warning(msg)
  800. char *msg ;
  801. {
  802.    ip_putlit("Warning: ",err) ;
  803.    ip_puts(msg,err) ;
  804.    newline(err) ;
  805. }
  806.  
  807. /***********************************************/
  808.  
  809. IP_FILE *ip_fdopen(fd,buf,bufsiz,maxsiz,write)
  810. int fd ;
  811. char *buf ;
  812. int bufsiz, maxsiz, write ;
  813. {
  814.    IP_FILE *fp = (IP_FILE *)malloc(sizeof(IP_FILE)) ;
  815.    
  816.    if (fp)
  817.       {
  818.       fp->fd = fd ;
  819.       fp->buf = buf ;
  820.       fp->bufsize = bufsiz ;
  821.       fp->buf_maxsize = maxsiz ;
  822.       fp->bufpos = 0 ;
  823.       fp->bufoffset = 0 ;
  824.       fp->write = write ;
  825.       }
  826.    return fp ;
  827. }
  828.  
  829. /***********************************************/
  830.  
  831. IP_FILE *ip_open_write(name,trunc,buf,bufsiz)
  832. char *name ;
  833. char *buf ;
  834. int trunc ;
  835. int bufsiz ;
  836. {
  837.    int fd ;
  838.    
  839.    if (name && *name == '\0')
  840.       fd = 1 ;    /* open stdout */
  841.    else
  842.       {
  843. #ifdef __TURBOC__
  844.       if (trunc)
  845.      fd = _creat(name,0) ;     /* create with no attribute bits sets */
  846.       else
  847.      fd = _open(name,O_WRONLY) ;
  848. #else
  849.       if (trunc) trunc = O_TRUNC ;
  850.       fd = open(name,O_WRONLY|O_BINARY|O_CREAT|trunc,S_IREAD|S_IWRITE) ;
  851. #endif
  852.       if (fd == -1)
  853.      return 0 ;
  854.       if (!trunc)
  855.      lseek(fd,0L,SEEK_END) ;
  856.       }
  857.    return ip_fdopen(fd,buf,bufsiz,bufsiz,1) ;
  858. }
  859.  
  860. /***********************************************/
  861.  
  862. IP_FILE *ip_open_read(name,buf,bufsiz)
  863. char *name ;
  864. char *buf ;
  865. int bufsiz ;
  866. {
  867.    int fd, siz ;
  868.  
  869. #ifdef __TURBOC__
  870.    if ((fd = _open(name,O_RDONLY)) != -1)
  871. #else
  872.    if ((fd = open(name,O_RDONLY | O_BINARY,0)) != -1)
  873. #endif
  874.       {
  875.       siz = read(fd,buf,bufsiz) ;
  876.       if (siz == -1)
  877.      return 0 ;
  878.       return ip_fdopen(fd,buf,siz,bufsiz,0) ;
  879.       }
  880.    else
  881.       return 0 ;
  882. }
  883.  
  884. /***********************************************/
  885.  
  886. int ip_flush(fp)
  887. IP_FILE *fp ;
  888. {
  889.    if (fp->write && fp->bufpos)
  890.       {
  891.       if (fp->bufpos > fp->buf_maxsize)
  892.      fp->bufpos = fp->buf_maxsize ;
  893.       if (write(fp->fd,fp->buf,fp->bufpos) == -1)
  894.      return -1 ;
  895.       fp->bufpos = 0 ;
  896.       }
  897.    return 0 ;
  898. }
  899.  
  900. /***********************************************/
  901.  
  902. int ip_close(fp)
  903. IP_FILE *fp ;
  904. {
  905.    if (ip_flush(fp) == -1 || close(fp->fd) == -1)
  906.       return -1 ;
  907.    free(fp) ;
  908.    return 0 ;
  909. }
  910.  
  911. /***********************************************/
  912.  
  913. unsigned long ip_fgets(buf, max, fp)
  914. char *buf ;
  915. int max ;
  916. IP_FILE *fp ;
  917. {
  918.    unsigned long line_offset = fp->bufoffset + fp->bufpos ;
  919.    char *end ;
  920.    int len ;
  921.    int new_bufpos ;
  922.    char *fpbuf = fp->buf ;
  923.    int bufpos = fp->bufpos ;
  924.    
  925.    --max ;
  926.    if (bufpos + max < fp->bufsize)
  927.       {
  928.       end = (char *)memchr(fpbuf+bufpos,LINE_TERMINATOR,max) ;
  929.       if (end)
  930.      {
  931.      new_bufpos = (end-fpbuf) ;
  932.      len = new_bufpos++ - bufpos ;
  933.      /* eradicate rest of multi-character line terminator */
  934.      while (len > 0 && fpbuf[bufpos+len-1] <= ' ')
  935.         len-- ;
  936.      }
  937.       else
  938.      {
  939.      len = max ;
  940.      new_bufpos = bufpos + len ;
  941.      }
  942.       if (len)
  943.      memcpy(buf,fpbuf+bufpos,len) ;
  944.       buf[len] = '\0' ;
  945.       bufpos = new_bufpos ;
  946.       }
  947.    else
  948.       {
  949.       for (len = 1 ; len <= max ; len++)
  950.      {
  951.      *buf = fpbuf[bufpos++] ;
  952.      if (bufpos >= fp->bufsize)
  953.         {
  954.         if (fp->bufsize < fp->buf_maxsize)
  955.            {
  956.            fp->bufsize = bufpos = 0 ;
  957.            fpbuf[0] = '\0' ;  /* dummy value to ensure empty string */
  958.            }
  959.         else
  960.            {
  961.            fp->bufoffset += fp->buf_maxsize ;
  962.            fp->bufsize = read(fp->fd,fpbuf,fp->buf_maxsize) ;
  963.            bufpos = 0 ;
  964.            }
  965.         if (fp->bufsize <= 0)
  966.            {
  967.            line_offset = (unsigned long)-1 ; /* signal end of file */
  968.            if (*buf != LINE_TERMINATOR)
  969.           *buf++ = LINE_TERMINATOR;
  970.            break ;
  971.            }
  972.         }
  973.      if (*buf == LINE_TERMINATOR)
  974.         break ;
  975.      else
  976.         buf++ ;
  977.      }
  978.       if (len > max)       /* did we overflow before hitting EOL? */
  979.      *buf = '\0' ;       /* if yes, plug in the terminator */
  980.       else
  981.      /* eradicate rest of multi-character line terminator */
  982.      while (len-- > 0 && *buf <= ' ')
  983.         *buf-- = '\0' ;
  984.       }
  985.    fp->bufpos = bufpos ;
  986.    return line_offset ;
  987. }
  988.  
  989. /***********************************************/
  990.  
  991. int ip_write(buf, count, fp)
  992. char *buf ;
  993. int count ;
  994. IP_FILE *fp ;
  995. {
  996.    if (fp->bufpos + count < fp->buf_maxsize)
  997.       {
  998.       memcpy(fp->buf+fp->bufpos,buf,count) ;
  999.       fp->bufpos += count ;
  1000.       }
  1001.    else
  1002.       while (count > 0)
  1003.      {
  1004.      int partial = fp->buf_maxsize - fp->bufpos ;
  1005.  
  1006.      if (count < partial)
  1007.         partial = count ;
  1008.      memcpy(fp->buf+fp->bufpos,buf,partial) ;
  1009.      buf += partial ;
  1010.      fp->bufpos += partial ;
  1011.      count -= partial ;
  1012.      if (fp->bufpos >= fp->buf_maxsize && ip_flush(fp) == -1)
  1013.            return -1 ;
  1014.      }
  1015.    return 0 ;
  1016. }
  1017.  
  1018. /***********************************************/
  1019.  
  1020. #define indent_line(fp) if(indent_string)ip_write(indent_string,indent_len,fp)
  1021.  
  1022. /***********************************************/
  1023.  
  1024. void indent_to(where,fp)
  1025. int where ;
  1026. IP_FILE *fp ;
  1027. {
  1028.    where += indent ;
  1029.    while (where >= 8)
  1030.       {
  1031.       ip_putc('\t',fp) ;
  1032.       where -= 8 ;
  1033.       }
  1034.    if (where)
  1035.       ip_write("        ",where,fp) ;
  1036. }
  1037.  
  1038. /***********************************************/
  1039.  
  1040. void put_line(fp,len)
  1041. IP_FILE *fp ;
  1042. int len ;
  1043. {
  1044.    static char line[8] = { 196, 196, 196, 196, 196, 196, 196, 196 } ;
  1045.  
  1046.    if (IBM_chars)
  1047.       {
  1048.       while (len >= 8)
  1049.      {
  1050.      ip_write(line,8,fp) ;
  1051.      len -= 8 ;
  1052.      }
  1053.       if (len)
  1054.      ip_write(line,len,fp) ;
  1055.       }
  1056.    else
  1057.       {
  1058.       while (len >= 8)
  1059.      {
  1060.      ip_write("--------",8,fp) ;
  1061.      len -= 8 ;
  1062.      }
  1063.       if (len)
  1064.      ip_write("--------",len,fp) ;
  1065.       }
  1066. }
  1067.  
  1068. /***********************************************/
  1069.  
  1070. void HPPCL_put_line(fp,len)
  1071. IP_FILE *fp ;
  1072. int len ;
  1073. {
  1074.    ip_putlit(HPPCL_IBM_LN_A,fp) ;
  1075.    ip_puts(itoa((len * 25), num, 10),fp) ;
  1076.    ip_putlit(HPPCL_IBM_LN_B,fp) ;
  1077. }
  1078.  
  1079. /***********************************************/
  1080.  
  1081. void HPPCL_set_typeface(fp,typeface)
  1082. IP_FILE *fp ;
  1083. char *typeface ;
  1084. {
  1085.    ip_putlit(HPPCL_FONT_ON_A,fp) ;
  1086.    if (typeface)
  1087.       ip_puts(typeface,fp) ;
  1088.    else
  1089.       ip_putlit("8",fp) ;
  1090.    ip_putlit(HPPCL_FONT_ON_B,fp) ;
  1091. }
  1092.  
  1093. /***********************************************/
  1094.  
  1095. int is_keyword(s,keys,numkeys)
  1096. char *s ;
  1097. KEYWORDS *keys ;
  1098. unsigned int numkeys ;
  1099. {
  1100.    register int cmp ;
  1101.    register unsigned int i ;
  1102.    KEYWORDS *currkey ;
  1103.    int firstchar = *s ;
  1104.  
  1105.    do {
  1106.       i = numkeys / 2 ;
  1107.       currkey = &keys[i] ;
  1108.       cmp = (firstchar - currkey->name[0]) ;
  1109.       if (cmp == 0)
  1110.          cmp = memcmp(s,currkey->name,currkey->length) ;
  1111.       if (cmp < 0)
  1112.      numkeys = i ;
  1113.       else if (cmp > 0)
  1114.      {
  1115.      keys = currkey+1 ;
  1116.      numkeys -= i+1 ;
  1117.      }
  1118.       else
  1119.      return TRUE ;
  1120.       } while (numkeys) ;
  1121.    return FALSE ;
  1122. }
  1123.  
  1124. /***********************************************/
  1125.  
  1126. void output_line(line,fp)
  1127. char *line ;
  1128. IP_FILE *fp ;
  1129. {
  1130.    if (*line)
  1131.       {
  1132.       int pos = 0 ;
  1133.       int len = strlen(line) ;
  1134.       
  1135.       indent_line(fp) ;
  1136.       if (boldface)
  1137.      {
  1138.      if (start_of_entry(line) || start_of_table(line))
  1139.         {
  1140.         if (printer_bold)
  1141.            {
  1142.            ip_putcstr(&printer->bold_on,fp) ;
  1143.            ip_write(line,len,fp) ;
  1144.            ip_putcstr(&printer->bold_off,fp) ;
  1145.            newline(fp) ;
  1146.            return ;
  1147.            }
  1148.         else
  1149.            {
  1150.            ip_write(line,len,fp) ;
  1151.            ip_putc('\r',fp) ;
  1152.            indent_line(fp) ;
  1153.            }
  1154.         }
  1155.      else if (section_start(line))
  1156.         {
  1157.         pos = (char *)memchr(line,':',len) - line ;
  1158.         if (printer_bold)
  1159.            {
  1160.            ip_putcstr(&printer->bold_on,fp) ;
  1161.            ip_write(line,pos,fp) ;
  1162.            ip_putcstr(&printer->bold_off,fp) ;
  1163.            line += pos ;       /* adjust because no longer at left edge */
  1164.            len -= pos ;
  1165.            }
  1166.         else
  1167.            {
  1168.            ip_write(line,pos,fp) ;
  1169.            ip_putc('\r',fp) ;
  1170.            indent_line(fp) ;
  1171.            }
  1172.         }
  1173.      } /* boldface */
  1174.       if (indent & 7)  /* indenting by other than a multiple of 8 ? */
  1175.      {
  1176.      while (*line)
  1177.         {
  1178.         if (*line == '\t')
  1179.            {
  1180.            ip_write("        ",8-(pos&7),fp) ;
  1181.            pos = 0 ;   /* absolute column doesn't matter, only mod 8 */
  1182.            }
  1183.         else
  1184.            {
  1185.            ip_putc(*line,fp) ;
  1186.            pos++ ;
  1187.            }
  1188.         line++ ;
  1189.         }
  1190.      }
  1191.       else
  1192.      ip_write(line,len,fp) ;
  1193.       }
  1194.    newline(fp) ;
  1195. }
  1196.  
  1197. /***********************************************/
  1198.  
  1199. void get_raw_line(buf)
  1200. char *buf ;
  1201. {
  1202.    static char progress_indicator[] = "ii\r";
  1203.    IP_FILE *in ;
  1204.  
  1205.    buf[0] = '\0' ;
  1206.    if (out_of_files)
  1207.       return ;
  1208.    current_line_offset = ip_fgets(buf,MAXLINE,infile) ;
  1209.    if (current_line_offset == (unsigned long)-1)
  1210.       if (multi_file)
  1211.      {
  1212.      offset_adjust += lseek(infile->fd,0L,SEEK_END) ;
  1213.      input_file[input_file_namelen-1]++ ;
  1214.      ip_close(infile) ;
  1215.      if ((in = ip_open_read(input_file,infile_buf,sizeof(infile_buf)))
  1216.            != NULL)
  1217.         {
  1218.         infile = in ;
  1219.         current_line_offset = ip_fgets(buf,MAXLINE,infile) ;
  1220.         }
  1221.      else
  1222.         {
  1223.         out_of_files = TRUE ;
  1224.         return ;
  1225.         }
  1226.      }
  1227.       else
  1228.      out_of_files = TRUE ;
  1229.    if (start_of_entry(buf) && ((short*)buf)[2] != ((short*)progress_indicator)[0])
  1230.       {
  1231.       ((short*)progress_indicator)[0] = ((short*)buf)[2] ;
  1232.       ip_putlit(progress_indicator, err) ;
  1233.       }
  1234. }
  1235.  
  1236. /***********************************************/
  1237.  
  1238. int unwanted_section(buf)
  1239. char *buf ;
  1240. {
  1241.    char str[MAXLINE] ;
  1242.    FILT_LIST *p ;
  1243.  
  1244.    strcpy(str,buf) ;
  1245.    (void) strupr(str) ;
  1246.    if (strchr(cf_buffers[CF_EXCLUDE], cf_current_category))
  1247.       return TRUE ; /* section is not wanted */
  1248.    if (exclude_only)
  1249.       goto test_exclude ;
  1250.       /* include the section unless it is header-excluded */
  1251.    if (strchr(cf_buffers[CF_UNCONDITIONAL], cf_current_category))
  1252.       return FALSE ; /* section is unconditionally wanted */
  1253.    if (strchr(cf_buffers[CF_INCLUDE], cf_current_category))
  1254.       goto test_exclude ; /* section is wanted if not header-excluded */
  1255.    /* section may be wanted if an include string matches */
  1256.    for (p = includes ; p ; p = p->next)
  1257.       if (p->str && strstr(str, p->str) != NULL)
  1258.      goto test_exclude ;
  1259.    return TRUE ; /* no include match, the entry is not wanted */
  1260. test_exclude:
  1261.    if (strchr(cf_buffers[CF_OVERRIDE], cf_current_category))
  1262.       return FALSE ; /* overriding header exclutions, section wanted */
  1263.    /* if wanted here, set to TRUE if *any* exclude string matches */
  1264.    for (p = excludes ; p ; p = p->next)
  1265.       if (p->str && strstr(str, p->str) != NULL)
  1266.      return TRUE ;
  1267.    return FALSE ; /* not excluded, the section is wanted */
  1268. }
  1269.  
  1270. /***********************************************/
  1271.  
  1272. void get_line(buf)
  1273. char *buf ;
  1274. {
  1275.    static char next_line[MAXLINE] ;
  1276.    static int readahead = FALSE ;
  1277.  
  1278.    /* get the next line from the file, skipping unwanted entries */
  1279.    if (readahead)
  1280.       {
  1281.       strcpy(buf,next_line) ;
  1282.       readahead = FALSE ;
  1283.       }
  1284.    else
  1285.       {
  1286.       do {
  1287.      get_raw_line(buf) ;
  1288.      } while (!include_index_lines && index_line(buf)) ;
  1289.       if (section_file_start(buf))
  1290.      do {
  1291.         get_raw_line(buf) ;
  1292.         } while (!divider_line(buf)) ;
  1293.       if (do_filter && divider_line(buf))
  1294.      {
  1295.      /* if we read a divider line while filtering, we have to look ahead */
  1296.      strcpy(next_line,buf);
  1297.      while (divider_line(next_line))
  1298.         {
  1299.         strcpy(buf,next_line) ; /* we may be returning the divider */
  1300.         get_raw_line(next_line) ;
  1301.         if (start_of_entry(next_line)) /* is it an interrupt entry? */
  1302.            {
  1303.            cf_current_category = buf[8]; /* save the category character */
  1304.            if (unwanted_section(next_line))
  1305.               {
  1306.               while (!divider_line(next_line))
  1307.              get_raw_line(next_line) ;
  1308.               }
  1309.            else /* section is wanted, so return divider and then next line */
  1310.               readahead = TRUE ;
  1311.            }
  1312.         else
  1313.            readahead = TRUE ;
  1314.         }
  1315.      }
  1316.       }
  1317. }
  1318.  
  1319. /***********************************************/
  1320.  
  1321. void fill_buffer(lines,lines_per_page)
  1322. int lines, lines_per_page ;
  1323. {
  1324.    int i ;
  1325.  
  1326.    /* copy remainder, if any, from last page to top of current page */
  1327.    if (lines)
  1328.       for (i = lines ; i < lines_per_page ; i++)
  1329.      {
  1330.      strcpy(buffer[i-lines], buffer[i]) ;
  1331.      line_offsets[i-lines] = line_offsets[i] ;
  1332.      }
  1333.    else
  1334.       lines = lines_per_page ;
  1335.    for (i = lines_per_page - lines ; i < lines_per_page ; i++)
  1336.       {
  1337.       get_line(buffer[i]) ;
  1338.       line_offsets[i] = current_line_offset + offset_adjust ;
  1339.       }
  1340. }
  1341.  
  1342. /***********************************************/
  1343.  
  1344. int find_page_break(lines)
  1345. int lines ;
  1346. {
  1347.    int i ;
  1348.    char *buf ;
  1349.  
  1350.    for (i = 0 ; i < widow_length ; i++)
  1351.       {
  1352.       buf = buffer[lines-i-1] ;
  1353.       if (buf[0] == '\0' || divider_line(buf))
  1354.      return lines - i ;
  1355.       else if (section_start(buf))
  1356.      return lines - i - 1 ;
  1357.       }
  1358.    return lines ;
  1359. }
  1360.  
  1361. /***********************************************/
  1362.  
  1363. int summarize(line, pages_printed)
  1364. int line, pages_printed ;
  1365. {
  1366.    char *s, reg ;
  1367.    int i ;
  1368.    int max_descrip ;
  1369.    int len, numlen ;
  1370.  
  1371.    s = buffer[line] ;
  1372.    if (start_of_entry(s))
  1373.       {
  1374.       memcpy(summary_line," -- -- -- ",10) ;
  1375.       summary_line[1] = s[4] ;     /* output interrupt number */
  1376.       summary_line[2] = s[5] ;
  1377.       len = 4 ;
  1378.       s = buffer[line+1] ;
  1379.       while (*s && isspace(*s))
  1380.      s++ ;
  1381.       if (*s == 'A')
  1382.      {
  1383.      reg = s[1] ;
  1384.      while (*s && *s != '=')
  1385.         s++ ;
  1386.      s++ ;        /* skip the equal sign */
  1387.      while (*s && isspace(*s))
  1388.         s++ ;    /* skip the space between equal sign and number */
  1389.      if (isxdigit(*s) && isxdigit(s[1]))
  1390.         {
  1391.         if (reg == 'L')
  1392.            len += 3 ;
  1393.         summary_line[len++] = *s++ ;
  1394.         summary_line[len++] = *s++ ;
  1395.         if (reg == 'X')
  1396.            {
  1397.            len++ ;
  1398.            summary_line[len++] = *s++ ;
  1399.            summary_line[len] = *s ;
  1400.            }
  1401.         }
  1402.      }
  1403.       len = 10 ;
  1404.       if (page_numbers)
  1405.      {
  1406.      itoa(pages_printed,num,10) ;
  1407.      numlen = strlen(num) ;
  1408.      for (i = numlen ; i < 3 ; i++)
  1409.         summary_line[len++] = ' ' ;
  1410.      memcpy(summary_line+len,num,numlen) ;
  1411.      len += numlen ;
  1412.      summary_line[len++] = ' ' ;
  1413.      }
  1414.       s = buffer[line] + 7 ;    /* find function description */
  1415.       if (*s && *s != '-')    /* does the heading contain flags? */
  1416.      {
  1417.      while (*s && !isspace(*s))
  1418.         summary_line[len++] = *s++ ;
  1419.      summary_line[len++] = '>' ;
  1420.      summary_line[len++] = ' ' ;
  1421.      while (*s && *s != '-')
  1422.         s++ ;
  1423.      }
  1424.       while (*s && !isspace(*s))
  1425.      s++ ;
  1426.       while (*s && isspace(*s))
  1427.      s++ ;
  1428.       max_descrip = (page_width > sizeof(summary_line)-1) ? 
  1429.                    sizeof(summary_line)-1 : page_width ;
  1430.       while (len < max_descrip && *s)
  1431.      summary_line[len++] = *s++ ;
  1432.       summary_line[len] = '\0' ;
  1433.       summary_line_len = len ;
  1434.       return 1 ;
  1435.       }
  1436.    else
  1437.       return 0 ;
  1438. }
  1439.  
  1440. /***********************************************/
  1441.  
  1442. void start_format(line)
  1443. char *line ;
  1444. {
  1445.    indent_line(formats) ;
  1446.    (*printer->put_line)(formats,79) ;
  1447.    newline(formats) ;
  1448.    indent_line(formats) ;
  1449.    ip_puts(summary_line,formats) ;
  1450.    newline(formats) ;
  1451.    indent_line(formats) ;
  1452.    ip_putc('\t',formats) ;
  1453.    ip_puts(line+10,formats) ;
  1454.    newline(formats) ;
  1455.    echo_format = TRUE ;
  1456. }
  1457.  
  1458. /***********************************************/
  1459.  
  1460. void show_offset(line,fp)
  1461. int line ;
  1462. IP_FILE *fp ;
  1463. {
  1464.    char offset_string[12] ;
  1465.    int len ;
  1466.    
  1467.    ultoa(line_offsets[line],offset_string,16) ;
  1468.    len = strlen(offset_string) ;
  1469.    ip_write("00000000",8-len,fp) ;
  1470.    ip_write(offset_string,len,fp) ;
  1471. }
  1472.  
  1473. /***********************************************/
  1474.  
  1475. void add_table(i)
  1476. int i ;
  1477. {
  1478.    char firstchar ;
  1479.    char num[6] ;
  1480.    char *end ;
  1481.    int len ;
  1482.    int summary_width ;
  1483.    char found = FALSE ;
  1484.    
  1485.    prev_table++ ;
  1486.    firstchar = buffer[i][0] ;
  1487.    if (firstchar == 'C' || firstchar == 'V')  /* Call.. or Values... ? */
  1488.       {
  1489.       if (i > 0 && buffer[i-1][0] == '(')
  1490.      {
  1491.      memcpy(num,buffer[i-1]+7,4) ;
  1492.      num[4] = '\0' ;
  1493.      len = 4 ;
  1494.      found = TRUE ;
  1495.      }
  1496.       }
  1497.    else if (firstchar == 'B' || firstchar == 'F') /* Bitfields.. or Format..? */
  1498.       {
  1499.       end = strrchr(buffer[i+1]+7,')') ;   /* rule out Bit(s) as only match */
  1500.       if (end)
  1501.      {
  1502.      memcpy(num,end-4,4) ;
  1503.      num[4] = '\0' ;
  1504.      len = 4 ;
  1505.      found = TRUE ;
  1506.      }
  1507.       }
  1508.    if (!found)
  1509.       {
  1510.       itoa(prev_table,num,10) ;
  1511.       len = strlen(num) ;
  1512.       }
  1513.    indent_line(tables) ;
  1514.    if (show_offsets)
  1515.       show_offset(i,tables) ;
  1516.    ip_write(" 0000",5-len,tables) ;
  1517.    ip_write(num,len,tables);
  1518.    if (page_numbers)
  1519.       {
  1520.       summary_width = 13 ;
  1521.       while (summary_line[summary_width] != ' ')
  1522.      summary_width++ ;
  1523.       summary_width++ ;    /* include the blank we found */
  1524.       }
  1525.    else
  1526.       summary_width = 10 ;
  1527.    ip_write(summary_line,summary_width,tables) ;
  1528.    len = strlen(buffer[i])-1 ;
  1529.    if (len > page_width - summary_width - 5)
  1530.       len = page_width - summary_width - 5 ;
  1531.    ip_write(buffer[i],len,tables) ;
  1532.    newline(tables) ;
  1533. }
  1534.  
  1535. /***********************************************/
  1536.  
  1537. int make_description(desc,line)
  1538. char *desc ;
  1539. int line ;
  1540. {
  1541.    char *start = desc ;
  1542.    
  1543.    summarize(line,pages_printed) ;
  1544.    memcpy(desc,"INT ", 4) ;
  1545.    desc += 4 ;
  1546.    *desc++ = summary_line[1] ;
  1547.    *desc++ = summary_line[2] ;
  1548.    if (summary_line[4] != '-')
  1549.       {
  1550.       memcpy(desc,", AH=", 5) ;
  1551.       desc += 5 ;
  1552.       *desc++ = summary_line[4] ;
  1553.       *desc++ = summary_line[5] ;
  1554.       }
  1555.    if (summary_line[7] != '-')
  1556.       {
  1557.       memcpy(desc,", AL=", 5) ;
  1558.       desc += 5 ;
  1559.       *desc++ = summary_line[7] ;
  1560.       *desc++ = summary_line[8] ;
  1561.       }
  1562.    *desc = '\0' ;
  1563.    return (desc-start)+1 ;
  1564. }
  1565.  
  1566. /***********************************************/
  1567.  
  1568. char *determine_heading(last)
  1569. int last ;
  1570. {
  1571.    int i ;
  1572.    static char heading[MAXLINE] ;
  1573.    char save[25] ;
  1574.    char num[10] ;
  1575.  
  1576.    /* ugly hack to keep the combination of -H and -T from showing wrong page */
  1577.    /* numbers for tables--copy last summary line from previous page to safe */
  1578.    /* place before processing current page, then restore it */
  1579.    memcpy(save,summary_line,sizeof(save)) ;
  1580.    if (start_of_entry(buffer[0]))
  1581.       {
  1582.       header_first.len = make_description(header_first.desc,0) ;
  1583.       header_first.part = 1 ;
  1584.       header_first.first_on_page = TRUE ;
  1585.       }
  1586.    else if (header_last.part == 0)  /* very first entry? */
  1587.       {
  1588.       for (i = 0 ; i < last ; i++)
  1589.      if (start_of_entry(buffer[i]))
  1590.         {
  1591.         header_first.len = make_description(header_first.desc,i) ;
  1592.         header_first.part = 1 ;
  1593.         header_first.first_on_page = TRUE ;
  1594.         break ;
  1595.         }
  1596.       }
  1597.    else
  1598.       {
  1599.       header_first.len = header_last.len ;
  1600.       memcpy(header_first.desc,header_last.desc,header_last.len) ;
  1601.       header_first.part = header_last.part + 1 ;
  1602.       header_first.first_on_page = FALSE ;
  1603.       }
  1604.    /* assume entry spans entire page */
  1605.    header_last.len = header_first.len ;
  1606.    memcpy(header_last.desc,header_first.desc,header_first.len) ;
  1607.    header_last.part = header_first.part ;
  1608.    header_last.first_on_page = header_first.first_on_page ;
  1609.    /* find last entry on page */
  1610.    if (header_first.part > 0)
  1611.       {
  1612.       for (i = last-1 ; i > 0 ; i--)
  1613.      if (start_of_entry(buffer[i]))
  1614.         {
  1615.         header_last.len = make_description(header_last.desc,i) ;
  1616.         header_last.part = 1 ;
  1617.         header_last.first_on_page = FALSE ;
  1618.         break ;
  1619.         }
  1620.       memcpy(heading,header_first.desc,header_first.len) ;
  1621.       if (header_first.part > 1)
  1622.      {
  1623.      strcat(heading," (Part ") ;
  1624.      strcat(heading,itoa(header_first.part,num,10)) ;
  1625.      strcat(heading,")") ;
  1626.      }
  1627.       if (memcmp(header_first.desc,header_last.desc,header_last.len) != 0 ||
  1628.       header_first.part != header_last.part)
  1629.      {
  1630.      strcat(heading," to ") ;
  1631.      strcat(heading,header_last.desc) ;
  1632.      if (header_last.part > 1)
  1633.         {
  1634.         strcat(heading," (Part ") ;
  1635.         strcat(heading,itoa(header_last.part,num,10)) ;
  1636.         strcat(heading,")") ;
  1637.         }
  1638.      }
  1639.       memcpy(summary_line,save,sizeof(save)) ;
  1640.       return heading ; 
  1641.       }
  1642.    else /* no headings yet */
  1643.       {
  1644.       memcpy(summary_line,save,sizeof(save)) ;
  1645.       return NULL ;
  1646.       }
  1647. }
  1648.  
  1649. /***********************************************/
  1650.  
  1651. void print_buffer(last,body_lines,lines_per_page,total_lines,use_FF)
  1652. int last, body_lines, lines_per_page, total_lines ;
  1653. int use_FF ;
  1654. {
  1655.    int i, len ;
  1656.    int headpos ;
  1657.    int print_this_page = (pages_printed>=first_page && pages_printed<=last_page);
  1658.    
  1659.    pages_printed++ ;
  1660.    if (do_headers)
  1661.       {
  1662.       char *heading ;
  1663.       
  1664.       if ((heading = determine_heading(last)) != NULL)
  1665.      {
  1666.      if (print_this_page)
  1667.         {
  1668.         len = strlen(heading) ;
  1669.         headpos = 40-len/2 ;
  1670.         indent_to(headpos,outfile) ;
  1671.         if (boldface)
  1672.            {
  1673.            if (printer_bold)
  1674.           {
  1675.           ip_putcstr(&printer->bold_on,outfile) ;
  1676.           ip_write(heading,len,outfile) ;
  1677.           ip_putcstr(&printer->bold_off,outfile) ;
  1678.           }
  1679.            else
  1680.           {
  1681.           ip_write(heading,len,outfile) ;
  1682.           ip_putc('\r',outfile) ;
  1683.           indent_to(headpos,outfile) ;
  1684.           ip_write(heading,len,outfile) ;
  1685.           }
  1686.            }
  1687.         else
  1688.            ip_write(heading,len,outfile) ;
  1689.         }
  1690.      }
  1691.       newline(outfile) ;
  1692.       newline(outfile) ;
  1693.       }
  1694.    for (i = 0 ; i < last ; i++)
  1695.       {
  1696.       if (print_this_page)
  1697.      {
  1698.      char *line = buffer[i] ;
  1699.      if (*line)
  1700.         {
  1701.         if (!keep_divider_lines && divider_line(line))
  1702.            {
  1703.            indent_line(outfile) ;
  1704.            (*printer->put_line)(outfile,79) ;
  1705.            newline(outfile) ;
  1706.            echo_format = FALSE ;
  1707.            }
  1708.         else
  1709.            {
  1710.            output_line(line, outfile) ;
  1711.            if (echo_format)
  1712.           output_line(line,formats) ;
  1713.            }
  1714.         }
  1715.      else
  1716.         {
  1717.         newline(outfile) ;
  1718.         echo_format = FALSE ;
  1719.         }
  1720.      }
  1721.       /* need summary lines if doing summary, formats, or table index */
  1722.       if (need_summary)
  1723.      {
  1724.      if (summarize(i,pages_printed) && do_summary && summary)
  1725.         {
  1726.         if (show_offsets)
  1727.            show_offset(i,summary) ;
  1728.         ip_write(summary_line,summary_line_len,summary) ;
  1729.         newline(summary) ;
  1730.         }
  1731.      if (do_formats && memcmp(buffer[i],"Format ",7) == 0)
  1732.         start_format(buffer[i]) ;
  1733.      if (do_tables && start_of_table(buffer[i]))
  1734.         add_table(i) ;
  1735.      }
  1736.       }
  1737.    if (print_this_page)
  1738.       {
  1739.       if (page_numbers)
  1740.      {
  1741.      for (i = last ; i <= body_lines ; i++)
  1742.         newline(outfile) ;
  1743.      itoa(pages_printed, num, 10) ;
  1744.      i = strlen(num) ;
  1745.      if (!duplex)
  1746.         indent_to(38-i/2,outfile) ;
  1747.      else if (pages_printed & 1)        /* odd-numbered page? */
  1748.         indent_to(75-i/2,outfile) ;
  1749.      else
  1750.         indent_to(2,outfile) ;
  1751.      ip_putlit("- ", outfile) ;
  1752.      ip_write(num, i, outfile) ;
  1753.      ip_putlit(" -", outfile) ;
  1754.      newline(outfile) ;
  1755.      }
  1756.       if (use_FF)
  1757.      ip_putc('\f',outfile) ;
  1758.       else
  1759.      for (i = page_numbers?lines_per_page:last ; i<total_lines ; i++)
  1760.         newline(outfile) ;
  1761.       if (duplex)
  1762.      {
  1763.      if (pages_printed & 1)           /* next page even or odd? */
  1764.         ip_putcstr(&printer->marginl, outfile) ;    /* even page */
  1765.      else
  1766.         ip_putcstr(&printer->marginr, outfile) ;    /* odd page */
  1767.      }
  1768.       }
  1769. }
  1770.  
  1771. /***********************************************/
  1772.  
  1773. void display_printers()
  1774. {
  1775.    int i ;
  1776.    
  1777.    ip_putlit("Valid printer names are:",err) ;
  1778.    newline(err) ;
  1779.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1780.       {
  1781.       ip_putc('\t',err) ;
  1782.       ip_puts(printers[i].name,err) ;
  1783.       newline(err) ;
  1784.       }
  1785.    ip_putlit("When entering the printer name, use either a dash or an",err) ;
  1786.    newline(err) ;
  1787.    ip_putlit("underscore in place of blanks.  Case is ignored, and the",err) ;
  1788.    newline(err) ;
  1789.    ip_putlit("name may be abbreviated to the shortest unique prefix.",err) ;
  1790.    newline(err) ;
  1791.    exit(1) ;
  1792. }
  1793.  
  1794. /***********************************************/
  1795.  
  1796. void select_printer(name)
  1797. char *name ;
  1798. {
  1799.    int i, len, prt = -1 ;
  1800.    
  1801.    len = strlen(name) ;
  1802.    for (i = 0 ; i < len ; i++)        /* convert dashes and underscores to blanks */
  1803.       if (name[i] == '-' || name[i] == '_')
  1804.      name[i] = ' ' ;
  1805.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1806.       if (strnicmp(name,printers[i].name,len) == 0)
  1807.      if (prt == -1)
  1808.         prt = i ;
  1809.      else
  1810.         fatal("Ambiguous printer name!  Use -P? to list printers.") ;
  1811.    if (prt == -1)
  1812.       fatal("Unknown printer name!  Use -P? to list printers.") ;
  1813.    else
  1814.       printer = &printers[prt] ;
  1815. }
  1816.  
  1817. /***********************************************/
  1818.  
  1819. void add_category_filter_info(filter, str)
  1820. CF_ENUM filter ;
  1821. char *str ;
  1822. /* insert category filter characters into proper buffer, provided they do
  1823.    not appear in other filter buffers
  1824. */
  1825. {
  1826.    static char err_msg[] =
  1827.     "Character \"x\" appears in more than one category filter string";
  1828. #define err_char_pos 11 /* position of x in err_msg */
  1829.    CF_ENUM f ;
  1830.    int i = 0, len = strlen(cf_buffers[filter]) ;
  1831.    char c, errmsg[80] ;
  1832.  
  1833.    while ((c = str[i++]) > ' ' && len < CF_BUFFER_SIZE)
  1834.       {
  1835.       for (f = filter; ; )
  1836.      {
  1837.      if ((f = (f + 1) % CF_ENUM_SIZE) == filter)
  1838.        break; /* all other filters checked */
  1839.      if (strchr(cf_buffers[f], c))
  1840.         {
  1841.         err_msg[err_char_pos] = c ;
  1842.         fatal(err_msg) ;
  1843.         }
  1844.      }
  1845.      cf_buffers[filter][len++] = c;
  1846.       }
  1847. #undef err_char_pos
  1848. }
  1849.  
  1850. /***********************************************/
  1851.  
  1852. FILT_LIST *add_filter_info(list,str)
  1853. FILT_LIST *list ;
  1854. char *str ;
  1855. {
  1856.    FILT_LIST *newfilt ;
  1857.    int len = strlen(str)+1 ;
  1858.    
  1859.    if ((newfilt = (FILT_LIST *)malloc(sizeof(struct filter_list)+len))
  1860.       != NULL)
  1861.       {
  1862.       newfilt->next = list ;
  1863.       memcpy(newfilt->str,str,len) ;
  1864.       strupr(newfilt->str) ;
  1865.       }
  1866.    else
  1867.       fatal("out of memory") ;
  1868.    return newfilt ;
  1869. }
  1870.  
  1871. /***********************************************/
  1872.  
  1873. void build_filter_lists(file)
  1874. char *file ;
  1875. {
  1876.    static char err_msg[] = "Unknown command \"x\" in filter file";
  1877. #define err_char_pos 17 /* position of x in err_msg */
  1878.    IP_FILE *fp ;
  1879.    char buf[MAXLINE] ;
  1880.    int len ;
  1881.    long result ;
  1882.  
  1883.    if ((fp = ip_open_read(file,filter_buf,sizeof(filter_buf))) == NULL)
  1884.       {
  1885.       warning("unable to open filtering file, will print entire list.") ;
  1886.       do_filter = FALSE ;
  1887.       }
  1888.    else /* OK, file is open, so start reading */
  1889.       {
  1890.       do {
  1891.      buf[0] = '\0' ;
  1892.      result = ip_fgets(buf, sizeof(buf), fp) ;
  1893.      len = strlen(buf) ;
  1894.      if (len > 1)
  1895.         {
  1896.         switch (buf[0])
  1897.            {
  1898.            case '+':
  1899.           includes = add_filter_info(includes,buf+1) ;
  1900.           goto include_too ;
  1901.            case '-':
  1902.           excludes = add_filter_info(excludes,buf+1) ;
  1903.           break ;
  1904.            case CF_EXCLUDE_CHAR:
  1905.           add_category_filter_info(CF_EXCLUDE, buf+1) ;
  1906.           break ;
  1907.            case CF_UNCONDITIONAL_CHAR:
  1908.           add_category_filter_info(CF_UNCONDITIONAL, buf+1) ;
  1909.           goto include_too ;
  1910.            case CF_INCLUDE_CHAR:
  1911.           add_category_filter_info(CF_INCLUDE, buf+1) ;
  1912.           goto include_too ;
  1913.            case CF_OVERRIDE_CHAR:
  1914.           add_category_filter_info(CF_OVERRIDE, buf+1) ;
  1915.           break ;
  1916.            case '#':        /* comment lines */
  1917.           break ;
  1918.            default:
  1919.           err_msg[err_char_pos] = buf[0] ;
  1920.           fatal(err_msg) ;
  1921.      include_too:
  1922.           exclude_only = FALSE;
  1923.            }
  1924.         }
  1925.      } while (result != -1) ;
  1926.       ip_close(fp) ;
  1927.       do_filter = TRUE ;
  1928.       }
  1929. #undef err_char_pos
  1930. }
  1931.  
  1932. /***********************************************/
  1933.  
  1934. void write_summary_header(fp,title,show_offsets,show_table)
  1935. IP_FILE *fp ;
  1936. char *title ;
  1937. int show_offsets, show_table ;
  1938. {
  1939.    /* set up the printer */
  1940.    ip_putcstr(&printer->init1,fp) ;
  1941.    ip_putcstr(&printer->init2,fp) ;
  1942.    ip_putcstr(&printer->marginc,fp) ;
  1943.    /* now start writing the actual header */
  1944.    indent_to(show_offsets?8:0,fp) ;
  1945.    ip_putlit("\t\t\t\t",fp) ;
  1946.    ip_puts(title,fp) ;
  1947.    newline(fp) ;
  1948.    indent_to(show_offsets?8:0,fp) ;
  1949.    ip_putlit("\t\t\t\t",fp) ;
  1950.    (*printer->put_line)(fp,strlen(title)) ;
  1951.    newline(fp) ;
  1952.    newline(fp) ;
  1953.    indent_line(fp) ;
  1954.    if (show_offsets)
  1955.       ip_putlit("Offset  ", fp) ;
  1956.    if (show_table)
  1957.       ip_putlit("Tbl# ",fp) ;
  1958.    ip_putlit("INT AH AL", fp) ;
  1959.    if (page_numbers)
  1960.       ip_putlit(" Page", fp) ;
  1961.    ip_putlit("\t\t\tDescription", fp) ;
  1962.    newline(fp) ;
  1963.    indent_line(fp) ;
  1964.    (*printer->put_line)(fp,page_width+(show_offsets?8:0)) ;
  1965.    newline(fp) ;
  1966. }
  1967.  
  1968. /***********************************************/
  1969.  
  1970. static void reset_printer_and_close(fp)
  1971. IP_FILE *fp ;
  1972. {
  1973.    ip_putcstr(&printer->term1,fp) ;
  1974.    ip_putcstr(&printer->term2,fp) ;
  1975.    ip_close(fp) ;
  1976. }
  1977.  
  1978. /***********************************************/
  1979.  
  1980. int _Cdecl main(argc,argv)
  1981. int argc ;
  1982. char *argv[] ;
  1983. {
  1984.    int lines_per_page = -1 ;
  1985.    int total_lines = -1 ;
  1986.    int use_FF = TRUE ;
  1987.    int last_line ;
  1988.    int body_lines ;
  1989.    char *typeface = NULL ;
  1990.    char *summary_file = NULL ;
  1991.    char *table_file = NULL ;
  1992.    char *formats_file = NULL ;
  1993.    char *filter_file = NULL ;
  1994.    char *last_page_num ;
  1995.  
  1996.    err = ip_fdopen(2,stderr_buf,sizeof(stderr_buf),sizeof(stderr_buf),1) ;
  1997.    ip_putlit("INTPRINT v", err) ;
  1998.    ip_putlit(VERSION, err) ;
  1999.    ip_putlit(" by Ralf Brown and others.  Donated to the Public Domain.",err) ;
  2000.    newline(err) ;
  2001.    ip_flush(err) ;
  2002.    if (argc == 1 && isatty(0))
  2003.       usage() ;      /* give help if invoked with no args and keybd input */
  2004.    while (argc >= 2 && argv[1][0] == '-')
  2005.       {
  2006.       switch (argv[1][1])
  2007.      {
  2008.      case 'B':
  2009.         printer_bold = TRUE ;
  2010.         /* fall through to -b */
  2011.      case 'b':
  2012.         boldface = TRUE ;
  2013.         break ;
  2014.      case 'd':
  2015.         duplex = TRUE ;
  2016.         break ;
  2017.      case 'e':
  2018.         indent = 8 ;
  2019.         page_width = 87 ;  /* 96 - indent - 1 right margin */
  2020.         break ;
  2021.      case 'f':
  2022.         formats_file = argv[1]+2 ;
  2023.         break ;
  2024.      case 'F':
  2025.         filter_file = argv[1]+2 ;
  2026.         break ;
  2027.      case 'H':   /* page headers */
  2028.         do_headers = TRUE ;
  2029.         break ;
  2030.      case 'i':
  2031.         indent = atoi(argv[1]+2) ;
  2032.         break ;
  2033.      case 'I':
  2034.         IBM_chars = TRUE ;
  2035.         break ;
  2036.      case 'k':
  2037.         keep_divider_lines = TRUE ;
  2038.         break ;
  2039.      case 'l':
  2040.         lines_per_page = atoi(argv[1]+2) ;
  2041.         break ;
  2042.      case 'L':
  2043.         total_lines = atoi(argv[1]+2) ;
  2044.         break ;
  2045.      case 'm':
  2046.         multi_file = TRUE ;
  2047.         break ;
  2048.      case 'n':
  2049.         pages_printed = atoi(argv[1]+2) ;
  2050.         break ;
  2051.      case 'P':
  2052.         if (argv[1][2] == '?')
  2053.            display_printers() ;
  2054.         else
  2055.            select_printer(argv[1]+2) ;
  2056.         break ;
  2057.      case 'p':
  2058.         page_numbers = TRUE ;
  2059.         break ;
  2060.      case 'r':
  2061.         first_page = atoi(argv[1]+2) ;
  2062.         last_page_num = strchr(argv[1]+2, ':') ;
  2063.         last_page = last_page_num ? atoi(last_page_num+1) : 0 ;
  2064.         if (last_page == 0)
  2065.            last_page = ~0 ;
  2066.         break ;
  2067.      case 's':
  2068.         summary_file = argv[1]+2 ;
  2069.         break ;
  2070.      case 't':
  2071.         typeface = argv[1]+2 ;
  2072.         break ;
  2073.      case 'T':
  2074.         table_file = argv[1]+2 ;
  2075.         break ;
  2076.      case 'V':
  2077.         show_offsets = IBM_chars = TRUE ;
  2078.         break ;
  2079.      case 'w':
  2080.         widow_length = atoi(argv[1]+2) ;
  2081.         break ;
  2082.      case 'x':
  2083.         include_index_lines = TRUE ;
  2084.         break ;
  2085.      default:
  2086.         usage() ;
  2087.      }
  2088.       argv++ ;
  2089.       argc-- ;
  2090.       }
  2091.    if (printer == NULL)
  2092.       select_printer("default") ;
  2093.    /* apply any necessary overrides to parameters */
  2094.    if (printer->indent != -1)
  2095.       indent = printer->indent ;
  2096.    if (lines_per_page < 0)
  2097.       lines_per_page = printer->lines_per_page ;
  2098.    if (total_lines <= 0)
  2099.       total_lines = printer->page_length ;
  2100.    if (page_width <= 0)
  2101.       page_width = printer->page_width ;
  2102.    if (show_offsets && page_width < 80)
  2103.       page_width = 80 ;
  2104.    if (printer->flag)
  2105.       *(printer->flag) = TRUE ;
  2106.    if (cstrlen(&printer->bold_on) == 0)     /* control sequences for bold? */
  2107.       printer_bold = FALSE ;        /* if not, don't try to use them */
  2108.    /* build the indent string */
  2109.    if (indent)
  2110.       {
  2111.       char *t ;
  2112.       int ind = indent ;
  2113.  
  2114.       indent_len = indent/8 + indent%8 ;
  2115.       t = indent_string = (char *)malloc(indent_len+1) ;
  2116.       while (ind >= 8)
  2117.      {
  2118.      *t++ = '\t' ;
  2119.      ind -= 8 ;
  2120.      }
  2121.       while (ind > 0)
  2122.      {
  2123.      *t++ = ' ' ;
  2124.      ind-- ;
  2125.      }
  2126.       }
  2127.    /* open the summary file, if any */
  2128.    if (summary_file && *summary_file)
  2129.       if ((summary = ip_open_write(summary_file,!pages_printed,summary_buf,
  2130.                    sizeof(summary_buf)))
  2131.         != NULL)
  2132.      do_summary = TRUE ;
  2133.       else
  2134.      warning("unable to open summary file") ;
  2135.    /* open the table index file, if any */
  2136.    if (table_file && *table_file)
  2137.       if ((tables = ip_open_write(table_file,!pages_printed,tables_buf,
  2138.                   sizeof(tables_buf)))
  2139.         != NULL)
  2140.      do_tables = TRUE ;
  2141.       else
  2142.      warning("unable to open table index file") ;
  2143.    /* open the data formats file, if any */
  2144.    if (formats_file && *formats_file)
  2145.       if ((formats = ip_open_write(formats_file,!pages_printed,formats_buf,
  2146.                    sizeof(formats_buf)))
  2147.         != NULL)
  2148.      do_formats = TRUE ;
  2149.       else
  2150.      warning("unable to open formats file") ;
  2151.    need_summary = (do_summary || do_formats || do_tables) ;
  2152.    /* initialize filtering data, if specified */
  2153.    if (filter_file && *filter_file)
  2154.       build_filter_lists(filter_file) ;
  2155.    if (total_lines <= lines_per_page)
  2156.       {
  2157.       total_lines = lines_per_page ;
  2158.       use_FF = TRUE ;
  2159.       }
  2160.    else
  2161.       use_FF = FALSE ;
  2162.    if (argc == 2 || argc == 3)
  2163.       {
  2164.       input_file = argv[1] ;
  2165.       input_file_namelen = strlen(input_file) ;
  2166.       if ((infile = ip_open_read(input_file,infile_buf,sizeof(infile_buf))) == NULL)
  2167.      fatal("unable to open input file") ;
  2168.       if (argc == 3)
  2169.      {
  2170.      outfile = ip_open_write(argv[2],!pages_printed,outfile_buf,
  2171.                  sizeof(outfile_buf)) ;
  2172.      if (outfile == NULL)
  2173.         fatal("unable to open output file") ;
  2174.      }
  2175.       else
  2176.      outfile = ip_open_write("",0,outfile_buf,sizeof(outfile_buf)) ;
  2177.       }
  2178.    else
  2179.       usage() ;
  2180.    if (lines_per_page > MAXPAGE)
  2181.       {
  2182.       ip_putlit("Surely you jest!  I can't handle pages that long.",err) ;
  2183.       newline(err) ;
  2184.       newline(err) ;
  2185.       usage() ;
  2186.       }
  2187.    else if (lines_per_page == 0) /* infinite page? */
  2188.       {
  2189.       widow_length = 0 ;
  2190.       if (total_lines <= 0)
  2191.      total_lines = MAXPAGE ;
  2192.       lines_per_page = total_lines ;
  2193.       use_FF = do_headers = page_numbers = FALSE ;
  2194.       }
  2195.    else
  2196.       {
  2197.       if (lines_per_page < 20)
  2198.      {
  2199.      ip_putlit("Surely your printer can handle at least 20 lines per page!",
  2200.            err) ;
  2201.      newline(err) ;
  2202.      ip_putlit("Adjusting page length....",err) ;
  2203.      newline(err) ;
  2204.      lines_per_page = 20 ;
  2205.      }
  2206.       if (widow_length < 3 || widow_length > lines_per_page / 2)
  2207.      {
  2208.      ip_putlit("Widow lines (-w) must be set to at least 3 and at most one-half of the",err) ;
  2209.      newline(err) ;
  2210.      ip_putlit("page length.  Using default of 8 lines.",err) ;
  2211.      newline(err) ;
  2212.      widow_length = 8 ;
  2213.      }
  2214.       }
  2215.    /* set up the printer */
  2216.    ip_putcstr(&printer->init1,outfile) ;
  2217.    ip_putcstr(&printer->init2,outfile) ;
  2218.    if (printer->set_typeface)
  2219.       (*printer->set_typeface)(outfile,typeface) ;
  2220.    if (duplex)
  2221.       {
  2222.       ip_putcstr(&printer->duplex_on,outfile) ;
  2223.       if (pages_printed & 1)          /* next page odd or even? */
  2224.      ip_putcstr(&printer->marginl,outfile) ;    /* even */
  2225.       else
  2226.      ip_putcstr(&printer->marginr,outfile) ;    /* odd */
  2227.       }
  2228.    else
  2229.       ip_putcstr(&printer->marginc,outfile) ;    /* non-duplex, so center */
  2230.    /* start the auxiliary files if this is the first part processed */
  2231.    if (pages_printed == 0)
  2232.       {
  2233.       /* start the summary file */
  2234.       if (do_summary)
  2235.      write_summary_header(summary,"Interrupt Summary",show_offsets,FALSE) ;
  2236.       /* start the table index file */
  2237.       if (do_tables)
  2238.      write_summary_header(tables,"Table Summary",show_offsets,TRUE) ;
  2239.       /* start the data formats file */
  2240.       if (do_formats)
  2241.      write_summary_header(formats,"Data Structure Formats",FALSE,FALSE) ;
  2242.       }
  2243.    if (page_numbers)
  2244.       body_lines = lines_per_page - 2 ;
  2245.    else
  2246.       body_lines = lines_per_page ;
  2247.    if (do_headers)
  2248.       body_lines -= 2 ;
  2249.    last_line = 0 ;
  2250.    while (!out_of_files)
  2251.       {
  2252.       fill_buffer(last_line,body_lines) ;
  2253.       last_line = find_page_break(body_lines) ;
  2254.       print_buffer(last_line,body_lines,lines_per_page,total_lines,use_FF) ;
  2255.       }
  2256.    if (last_line < body_lines)
  2257.       {
  2258.       int i ;
  2259.       
  2260.       for (i = last_line ; i < body_lines ; i++)
  2261.      {
  2262.      strcpy(buffer[i-last_line], buffer[i]) ;
  2263.      line_offsets[i-last_line] = line_offsets[i] ;
  2264.      }
  2265.       print_buffer(body_lines-last_line,body_lines,lines_per_page,total_lines,
  2266.            use_FF) ;
  2267.       }
  2268.    ip_close(infile) ;
  2269.    /* reset the printer */
  2270.    reset_printer_and_close(outfile) ;
  2271.    ip_puts(itoa(pages_printed, num, 10), err) ;
  2272.    ip_putlit(" pages", err) ;
  2273.    if (do_summary)
  2274.       reset_printer_and_close(summary) ;
  2275.    if (do_tables)
  2276.       {
  2277.       ip_putlit(", ", err) ;
  2278.       ip_puts(itoa(prev_table, num, 10), err) ;
  2279.       ip_putlit(" tables", err) ;
  2280.       reset_printer_and_close(tables) ;
  2281.       }
  2282.    if (do_formats)
  2283.       reset_printer_and_close(formats) ;
  2284.    newline(err) ;
  2285.    ip_close(err) ;
  2286.    return 0 ;
  2287. }
  2288.